#include "scheduler.h"

static bool debug = false;

namespace zsylar 
{

static thread_local Scheduler* t_scheduler = nullptr;   // 当前线程的调度器

// 获取当前线程的调度器
Scheduler* Scheduler::GetThis()
{
    return t_scheduler;
}

// 设置当前线程的调度器
void Scheduler::SetThis()
{
    t_scheduler = this;
}

// 构造函数
Scheduler::Scheduler(size_t threads, bool use_caller, const std::string &name)
    : m_useCaller(use_caller), m_name(name)
{
    assert(threads > 0 && Scheduler::GetThis() == nullptr);
    SetThis();  // 设置当前线程的调度器
    Thread::SetName(m_name);  // 设置线程名称

    // 使用主线程当作工作线程
    if (use_caller) 
    {
        // 减少线程数
        threads--;
        // 创建主协程
        Fiber::GetThis();
        // 创建调度协程
        // false -> 该调度协程退出后将返回主协程
        m_schedulerFiber.reset(new Fiber(std::bind(&Scheduler::run, this), 0, false)); 
        Fiber::SetSchedulerFiber(m_schedulerFiber.get());  // 设置调度协程
        m_rootThread = Thread::GetThreadId();  // 获取主线程ID
        m_threadIds.push_back(m_rootThread);  // 将主线程ID添加到线程ID列表
    }

    // 设置线程数
    m_threadCount = threads;
    if (debug) std::cout << "Scheduler::Scheduler() success\n";
}

// 析构函数
Scheduler::~Scheduler()
{
    assert(stopping() == true);  // 确保调度器已停止
    if (GetThis() == this) 
    {
        t_scheduler = nullptr;  // 清除当前线程的调度器
    }
    if (debug) std::cout << "Scheduler::~Scheduler() success\n";
}

// 启动调度器-创建线程池
void Scheduler::start()
{
    std::lock_guard<std::mutex> lock(m_mutex);  // 锁定互斥锁
    if (m_stopping) 
    {
        std::cerr << "Scheduler is stopped" << std::endl;
        return;  // 如果正在停止，则不启动
    }

    assert(m_threads.empty());  // 确保线程池为空
    m_threads.resize(m_threadCount);  // 调整线程池大小

    for (size_t i = 0; i < m_threadCount; i++) 
    {
        // 创建新的线程并绑定调度器的运行函数
        // 线程名称为 "Scheduler_i"，其中 i 是线程索引
        m_threads[i].reset(new Thread(std::bind(&Scheduler::run, this), m_name + "_" + std::to_string(i)));
        // 添加线程ID到列表
        m_threadIds.push_back(m_threads[i]->getId());  
    }
    if (debug) std::cout << "Scheduler::start() success\n";
}

void Scheduler::run()
{
    int thread_id = Thread::GetThreadId();  // 获取当前线程ID
    if (debug) std::cout << "Scheduler::run() starts in thread: " 
        << thread_id << std::endl;
    SetThis();  // 设置当前线程的调度器

    if (thread_id != m_rootThread)
    {
        Fiber::GetThis();  // 获取当前线程的协程
    }
    
    // 创建空闲协程
    std::shared_ptr<Fiber> idle_fiber = std::make_shared<Fiber>(std::bind(&Scheduler::idle, this));
    ScheduleTask task;  // 创建任务对象

    while (true)
    {
        task.reset();  // 重置任务对象
        bool tickle_me = false;  // 是否需要唤醒调度器

        {
            std::lock_guard<std::mutex> lock(m_mutex);  // 锁定互斥锁
            auto it = m_tasks.begin();  // 获取任务队列的迭代器
            while (it != m_tasks.end())
            {
                // 1. 遍历任务队列
                if (it->thread != -1 && it->thread != thread_id)
                {
                    it++;
                    tickle_me = true;  // 如果任务线程ID为-1或与当前线程ID匹配，则需要唤醒调度器
                    continue;  // 继续下一个任务
                }
                // 2. 取出任务
                assert(it->fiber || it->cb);  // 确保任务有协程或回调函数
                task = *it;  // 复制任务
                m_tasks.erase(it);  // 从任务队列中移除任务
                m_activeThreadCount++;  // 活动线程计数加1
                break;
            }
            tickle_me = tickle_me || (it != m_tasks.end());  // 如果任务队列不为空，则需要唤醒调度器
        }

        if (tickle_me)
        {
            tickle();  // 唤醒调度器
        }
        
        // 3. 执行任务
        if (task.fiber)
        {
            // 如果任务是协程
            {
                std::lock_guard<std::mutex> lock(task.fiber->m_mutex);  // 锁定协程的互斥锁
                if (task.fiber->getState() != Fiber::TERM)  // 如果协程未终止
                {
                    task.fiber->resume();  // 恢复协程执行
                }
            }
            m_activeThreadCount--;  // 活动线程计数减1
            task.reset();  // 重置任务对象
        }
        else if (task.cb)
        {
            // 如果任务是回调函数
            std::shared_ptr<Fiber> cb_fiber = std::make_shared<Fiber>(task.cb);  // 创建协程执行回调函数
            {
                std::lock_guard<std::mutex> lock(cb_fiber->m_mutex);  // 锁定协程的互斥锁
                cb_fiber->resume();  // 恢复协程执行
            }
            m_activeThreadCount--;  // 活动线程计数减1
            task.reset();  // 重置任务对象
        }
        // 4. 无任务 -> 执行空闲协程
        else
        {
            if (idle_fiber->getState() == Fiber::TERM)
            {
                if (debug) std::cout << "Idle fiber is terminated, exiting run()" << std::endl;
                break;  // 如果空闲协程已终止，则退出运行
            }
            m_idleThreadCount++;  // 空闲线程计数加1
            idle_fiber->resume();  // 恢复空闲协程执行
            m_idleThreadCount--;  // 空闲线程计数减1
        }
    }
}

// 停止调度器
void Scheduler::stop()
{
    if (debug) std::cout << "Scheduler::stop() starts in thread: "
        << Thread::GetThreadId() << std::endl;
    
    if (stopping()) 
    {
        return;  // 如果调度器已停止，则不执行任何操作
    }

    m_stopping = true;  // 设置调度器为停止状态
    if (m_useCaller)
    {
        assert(GetThis() == this);  // 确保当前线程是调度器线程
    }
    else
    {
        assert(GetThis() != this);  // 确保当前线程不是调度器线程
    }

    for (size_t i = 0; i < m_threadCount; i++)
    {
        tickle();  // 唤醒调度器
    }

    if (m_schedulerFiber)
    {
        tickle();  // 唤醒调度器以结束调度协程
    }

    if (m_schedulerFiber)
    {
        m_schedulerFiber->resume();  // 恢复调度协程执行
        if (debug) std::cout << "m_schedulerFiber ends in thread: "
            << Thread::GetThreadId() << std::endl;
    }

    std::vector<std::shared_ptr<Thread>> thrs;
    {
        std::lock_guard<std::mutex> lock(m_mutex);  // 锁定互斥锁
        thrs.swap(m_threads);  // 交换线程池，清空当前线程池
    }

    for (auto &i : thrs)
    {
        i->join();  // 等待所有线程结束
    }
    if (debug) std::cout << "Scheduler::stop() ends in thread: "
        << Thread::GetThreadId() << std::endl; 
}

// 唤醒调度器
void Scheduler::tickle()
{
    // 这里可以实现唤醒调度器的逻辑，例如通知调度器有新的任务到来
    // 具体实现取决于调度器的设计
}

// 空闲协程函数
void Scheduler::idle()
{
    while (!stopping())
    {
        if (debug) std::cout << "Scheduler::idle() in thread: "
            << Thread::GetThreadId() << std::endl;
        sleep(1);  // 休眠1秒，避免CPU占用过高
        Fiber::GetThis()->yield();  // 让出执行权，切换到其他协程
    }
}

// 检查调度器是否正在停止
bool Scheduler::stopping()
{
    std::lock_guard<std::mutex> lock(m_mutex);  // 锁定互斥锁
    return m_stopping && m_tasks.empty() && m_activeThreadCount == 0;  // 返回是否正在停止且没有任务和活动线程
}
    
}